package com.kfm.base.io.b;

import java.io.*;
import java.util.Arrays;

public class FileCombiner {

    public static void main(String[] args) {
        File dir = new File("d:/io/cutter");

        File file = new File("d:/io/可惜没如果_copy.mp4");

        long size = join(dir, file);
        System.out.println(size);

//        String path = "d:/io/cutter/10.kfm";
//        String path1 = "d:/io/cutter/2.kfm";
//
//        System.out.println(path.compareTo(path1));
    }

    /**
     * 将指定目录中的多个文件片段依次序合并到同一个文件中，并返回合并后的文件体积
     *
     * @param dir    存放文件片段的目录(即拆分文件后的N个小文件的存放目录)
     * @param target 表示合并后的文件的存放路径
     * @return 返回合并后的文件体积
     *
     *  合并后文件被损坏，原因：合并时子文件的顺序不对
     *  解决方案：
     *    1. 拆分时文件名按照顺序命名（单线程下可用时间戳做文件名）
     *    2. 根据文件名自定义排序规则
     */
    public static long join(final File dir, final File target) {
        long size = 0; // 声明用于统计合并后的文件体积的变量

        // 参数校验
        if (dir == null || !dir.isDirectory()) {
            return size;
        }

        // 参数校验
        if (target == null) {
            return size;
        }
        if (!target.getParentFile().exists()){
            target.getParentFile().mkdirs();
        }

        // 合并文件
        File[] files = dir.listFiles((file, name) -> name.endsWith(".kfm"));

        if (files != null && files.length > 0) { // 判断是否有文件片段
            // 保证顺序
            Arrays.sort(files, (f1, f2) -> {
                String name1 = f1.getName();
                String name2 = f2.getName();

                int index1 = Integer.parseInt(name1.split("\\.")[0]);
                int index2 = Integer.parseInt(name2.split("\\.")[0]);

                return index1 - index2;
            });
            try {
                FileOutputStream fos = new FileOutputStream(target); // 创建文件输出流
                for (File file : files) { // 遍历文件片段
                    if (file.length() <= Integer.MAX_VALUE - 8){ // 一次可以完全读取
                        FileInputStream fileInputStream = new FileInputStream(file);
                        byte[] bytes = fileInputStream.readAllBytes();

                        fos.write(bytes);

                        fileInputStream.close();
                    } else {
                        // 一次不能完全读取
                        FileInputStream fileInputStream = new FileInputStream(file);

                        while (fileInputStream.available() != 0){
                            byte[] bytes = new byte[Integer.MAX_VALUE - 8];
                            int readSize = fileInputStream.read(bytes);

                            fos.write(bytes, 0, readSize);
                        }

                        fileInputStream.close();
                    }
                    size += file.length();
                }
                fos.close();
            } catch (FileNotFoundException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        return size; // 返回合并后的文件体积
    }
}
